package in.muton.edushare.panels.assignment;

import in.muton.edushare.components.images.ProfileImage;
import in.muton.edushare.grading.panels.studentGrades.GradingUtil;
import in.muton.edushare.grading.panels.studentGrades.GradingUtil.ItemGradeHelper;
import in.muton.edushare.pages.EduShareBasePage;
import in.muton.edushare.pages.common.EdusharePanel;
import in.muton.edushare.url.EduShareURLPanel;
import in.muton.edushare.wicket.models.CayenneModel;
import in.muton.panels.paginator.EdusharePageNavigator;
import in.muton.wicket.component.IndicatingAjaxButton;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.CSSPackageResource;
import org.apache.wicket.markup.html.JavascriptPackageResource;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Check;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.CheckGroup;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.list.PageableListView;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

import com.edushare.common.constants.ApplicationConstants;
import com.edushare.common.dao.AssignmentsDAO;
import com.edushare.common.dao.FilesUploadedDAO;
import com.edushare.common.dao.UserAssignmentLinkDAO;
import com.edushare.common.util.DateTimeUtil;
import com.edushare.common.vo.Assignments;
import com.edushare.common.vo.CourseInstances;
import com.edushare.common.vo.FilesUploaded;
import com.edushare.common.vo.GradingItem;
import com.edushare.common.vo.UserAssignmentLink;
import com.edushare.common.vo.Users;

public class SubmittersList extends EdusharePanel {

	private static final long serialVersionUID = -3241666930161244855L;
	private IModel<Assignments> assnModel;
	private Integer filterBy = UserAssignmentLink.FILTER_NONE;
	private static Log log = LogFactory.getLog(SubmittersList.class);

	private static final int SHOW_ALL = 0;
	// private static final int SHOW_SUBMISSIONS = 1;
	private static final int SHOW_INTIME = 2;
	private static final int SHOW_LATE = 3;
	private static final int SHOW_PENDING = 4;
	// private static final int SHOW_DEFAULTERS = 5;
	private static final int SHOW_EVALUATED = 6;
	private static final int SHOW_NOT_EVALUATED = 7;

	public SubmittersList(String id, EduShareBasePage page, IModel<Assignments> assnModel) {
		super(id, assnModel, page);
		this.assnModel = assnModel;
		add(CSSPackageResource.getHeaderContribution(SubmittersList.class,
				"assignment.css"));
		add(JavascriptPackageResource.getHeaderContribution(
				SubmittersList.class, "SubmittersList.js"));
		loadPanel();
	}

	private void loadPanel() {

		final CheckGroup<UserAssignmentLink> assnGroup = new CheckGroup<UserAssignmentLink>(
				"assnGroup", new ArrayList<UserAssignmentLink>());
		Form<Void> form = new Form<Void>("submissionsAction") {

			private static final long serialVersionUID = -8842842648976739671L;

			@Override
			protected void onSubmit() {
				System.out.println("Form Submitted");
			}
		};
		add(form);

		Button deleteSelected = new Button("deleteSelected") {

			private static final long serialVersionUID = -5285888479699664554L;

			@Override
			public void onSubmit() {
				log.debug("=== Deleting user-assigment association ===");
				Iterator<UserAssignmentLink> it = assnGroup.getModelObject()
						.iterator();
				while (it.hasNext()) {
					UserAssignmentLink ual = it.next();
					it.remove();
					new UserAssignmentLinkDAO(getORMInterface())
							.deleteUserSubmissions(ual);
				}

				getORMInterface().commitAllChanges();
			}
		};

		deleteSelected.setOutputMarkupId(true).setMarkupId("deleteSelected");
		deleteSelected.add(new SimpleAttributeModifier("onclick",
				"return confirm('Unassigning will delete "
						+ "all the files submitted by selected users "
						+ "and users will no longer be able to submit "
						+ "a file to this assignment."
						+ "Do you want to continue?');"));
		form.add(deleteSelected);
		// deletion of assignee is ambiguous
		deleteSelected.setVisible(false);
		form.add(assnGroup);

		final WebMarkupContainer showAllSel = new WebMarkupContainer(
				"showAllSel");
		showAllSel.setVisible(false);

		assnGroup.add(new Link("showAll") {

			@Override
			public void onClick() {
				SubmittersList.this.filterBy = SHOW_ALL;
			}

			@Override
			protected void onBeforeRender() {
				if (SubmittersList.this.filterBy == SHOW_ALL)
					setEnabled(false);
				else
					setEnabled(true);
				super.onBeforeRender();
			}

		});

		assnGroup.add(new Link("showIntime") {

			@Override
			public void onClick() {
				SubmittersList.this.filterBy = SHOW_INTIME;
			}

			@Override
			protected void onBeforeRender() {
				if (SubmittersList.this.filterBy == SHOW_INTIME)
					setEnabled(false);
				else
					setEnabled(true);
				super.onBeforeRender();
			}

		});

		assnGroup.add(new Link("showLate") {

			@Override
			public void onClick() {
				SubmittersList.this.filterBy = SHOW_LATE;
			}

			@Override
			protected void onBeforeRender() {
				if (SubmittersList.this.filterBy == SHOW_LATE)
					setEnabled(false);
				else
					setEnabled(true);
				super.onBeforeRender();
			}

		});

		assnGroup.add(new Link("showPending") {

			@Override
			public void onClick() {
				SubmittersList.this.filterBy = SHOW_PENDING;
			}

			@Override
			protected void onBeforeRender() {
				if (SubmittersList.this.filterBy == SHOW_PENDING)
					setEnabled(false);
				else
					setEnabled(true);
				super.onBeforeRender();
			}

		});

		/*
		 * assnGroup.add(new Link("showDefaulters"){
		 * 
		 * @Override public void onClick() { SubmittersList.this.filterBy =
		 * SHOW_DEFAULTERS; }
		 * 
		 * });
		 */

		assnGroup.add(new Link("showEvaluated") {

			@Override
			public void onClick() {
				SubmittersList.this.filterBy = SHOW_EVALUATED;
			}

			@Override
			protected void onBeforeRender() {
				if (SubmittersList.this.filterBy == SHOW_EVALUATED)
					setEnabled(false);
				else
					setEnabled(true);
				super.onBeforeRender();
			}

		});

		assnGroup.add(new Link("showNotEvaluated") {

			@Override
			public void onClick() {
				SubmittersList.this.filterBy = SHOW_NOT_EVALUATED;
			}

			@Override
			protected void onBeforeRender() {
				if (SubmittersList.this.filterBy == SHOW_NOT_EVALUATED)
					setEnabled(false);
				else
					setEnabled(true);
				super.onBeforeRender();
			}

		});

		final WebMarkupContainer noItemDiv = new WebMarkupContainer("noItemDiv");
		noItemDiv.add(new Label("stts", new PropertyModel<String>(
				SubmittersList.this, "filterAsString"))
				.setEscapeModelStrings(false));
		PageableListView<IModel<UserAssignmentLink>> submissionsList = new PageableListView<IModel<UserAssignmentLink>>(
				"submCont",
				new PropertyModel<List<IModel<UserAssignmentLink>>>(
						SubmittersList.this, "submissions"),
				ApplicationConstants.PAGE_SIZE) {

			private static final long serialVersionUID = 5458837824914101622L;

			@Override
			protected void populateItem(
					final ListItem<IModel<UserAssignmentLink>> item) {
				CayenneModel<Users> umodel = new CayenneModel<Users>(item
						.getModelObject().getObject().getUser());
				Check<UserAssignmentLink> selectMe = new Check<UserAssignmentLink>(
						"selectMe", item.getModelObject());
				item.add(selectMe);
				item.add(new ProfileImage("uimage", umodel,
						ApplicationConstants.FILE_SUFFIX_ICON));
				EduShareURLPanel userLink = new EduShareURLPanel("usrLink",
						umodel);
				userLink.add(new AttributeAppender("class", true,
						new Model<String>("es-entity"), " "));
				item.add(userLink);
				item.add(new Label("submStat", new PropertyModel<String>(item
						.getModelObject(), "statusAsString")));
				item.add(new Label("submTime", new IModel<String>() {

					private static final long serialVersionUID = 3765227419623494940L;

					public String getObject() {
						if (item.getModelObject().getObject().getLastUpdated() == null) {
							return "No submissions yet";
						} else {
							return DateTimeUtil.formatDate(item
									.getModelObject().getObject()
									.getLastUpdated());
						}
					}

					public void setObject(String arg0) {
					}

					public void detach() {
					}
				}));
				item.add(new FeedbackFrag("feedbackPlaceholder",
						SubmittersList.this, item.getModelObject()));
				item.add(new SubmittedFiles("myFiles", SubmittersList.this,
						umodel));

			}

			@Override
			protected void onBeforeRender() {
				if (this.getList() == null || this.getList().size() < 1) {
					noItemDiv.setVisible(true);
				} else {
					noItemDiv.setVisible(false);
				}
				super.onBeforeRender();
			}

		};

		assnGroup.add(submissionsList);
		assnGroup.add(noItemDiv);
		assnGroup.add(new EdusharePageNavigator("asnPagination",
				submissionsList));
	}

	public List<IModel<UserAssignmentLink>> getSubmissions() {
		int subFilter = 0;
		int evalFilter = 0;

		/*
		 * if(this.filterBy==1){ subFilter =
		 * UserAssignmentLink.STATUS_SUBMISSION_DONE; evalFilter = 0; }
		 */

		switch (this.filterBy) {
		case SubmittersList.SHOW_ALL:
			subFilter = 0;
			evalFilter = 0;
			break;

		case SubmittersList.SHOW_INTIME:
			subFilter = UserAssignmentLink.STATUS_SUBMISSION_DONE;
			evalFilter = 0;
			break;

		case SubmittersList.SHOW_LATE:
			subFilter = UserAssignmentLink.STATUS_SUBMISSION_LATE;
			evalFilter = 0;
			break;

		case SubmittersList.SHOW_PENDING:
			subFilter = UserAssignmentLink.STATUS_SUBMISSION_PENDING;
			evalFilter = 0;
			break;

		/*
		 * case SubmittersList.SHOW_DEFAULTERS: subFilter =
		 * UserAssignmentLink.STATUS_SUBMISSION_NONE; evalFilter = 0; break;
		 */

		case SubmittersList.SHOW_EVALUATED:
			subFilter = 0;
			evalFilter = UserAssignmentLink.EVALUATED;
			break;

		case SubmittersList.SHOW_NOT_EVALUATED:
			subFilter = 0;
			evalFilter = UserAssignmentLink.NOT_EVALUATED;
			break;

		default:
			subFilter = 0;
			evalFilter = 0;
			break;
		}

		List<UserAssignmentLink> uall = (new UserAssignmentLinkDAO(
				getORMInterface()).getSubmittersList(
				this.assnModel.getObject(), subFilter, evalFilter));
		ArrayList<IModel<UserAssignmentLink>> uallmodel = new ArrayList<IModel<UserAssignmentLink>>();
		for (UserAssignmentLink ual : uall) {
			uallmodel.add(new CayenneModel<UserAssignmentLink>(ual));
		}
		return uallmodel;
	}

	/** Feedback fragment with Ajax Submission */
	public class FeedbackFrag extends Fragment {

		private IModel<UserAssignmentLink> ualModel;

		public FeedbackFrag(String id, MarkupContainer container,
				final IModel<UserAssignmentLink> ualModel) {
			super(id, "feedbackFrag", container, ualModel);
			this.ualModel = ualModel;
			Form<Void> form = new Form<Void>("fbForm") {
				private static final long serialVersionUID = 245881007717640150L;

				@Override
				protected void onSubmit() {
					getORMInterface().commitAllChanges();
				}
			};
			add(form);

			form.add(new TextArea<String>("fbText", new PropertyModel<String>(
					ualModel, "remarks")));
			final CheckBox isEvaluated = new CheckBox("isEval",
					new PropertyModel<Boolean>(this, "evaluationStatus"));
			form.add(isEvaluated);
			final WebMarkupContainer isUpdatedTick = new WebMarkupContainer(
					"isUpdated");
			isUpdatedTick.setOutputMarkupPlaceholderTag(true);
			form.add(isUpdatedTick);
			form.add(new TextField<String>("marksAwarded",
					new PropertyModel<String>(this, "marks")));
			form.add(new Label("total", assnModel.getObject().getGradingItem()
					.getMaxMarks().toString()));
			IndicatingAjaxButton updateFeedback = new IndicatingAjaxButton(
					"fbSubmit") {
				private static final long serialVersionUID = -831377207491088917L;

				@Override
				protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
				}
			};
			form.add(updateFeedback);
		}

		public String getMarks() {
			GradingItem item = ualModel.getObject().getAssignment()
					.getGradingItem();
			IModel<CourseInstances> instModel = new CayenneModel<CourseInstances>(
					assnModel.getObject().getCourseInstance());
			ItemGradeHelper ih = new GradingUtil(instModel)
					.getGradesByItemUser(ualModel.getObject().getUser(), item);
			return ih.marks + "";
		}

		public void setMarks(String marks) {
			GradingItem item = ualModel.getObject().getAssignment()
					.getGradingItem();
			log.debug("In setMarks : The grade is "+marks);
			IModel<CourseInstances> instModel = new CayenneModel<CourseInstances>(
					assnModel.getObject().getCourseInstance());
			GradingUtil util = new GradingUtil(instModel);
			ItemGradeHelper ih = util.getGradesByItemUser(ualModel.getObject()
					.getUser(), item);
			try{
				ih.marks = Double.parseDouble(marks);
				log.debug("In setMarks : The marks are "+ih.marks);
				if(!util.isValidMarks(ih.marks, item)){
					setError("Please provide valid marks between 0 and "+item.getMaxMarks());
					return;
				}
				log.debug("In setMarks : Saving marks "+ih.marks);
				util.saveMarks(ih);
			}catch(NumberFormatException n){
				setError("Please provide valid marks");
				log.debug("Error : Saving marks "+marks);
			}
		}

		public Boolean getEvaluationStatus() {
			if (/* ualModel.getObject().getEvaluationStat()==null || */ualModel
					.getObject().getEvaluationStat() == UserAssignmentLink.EVALUATED) {
				return true;
			} else {
				return false;
			}
		}

		public void setEvaluationStatus(Boolean status) {
			if (status) {
				ualModel.getObject().setEvaluationStat(
						UserAssignmentLink.EVALUATED);
			} else {
				ualModel.getObject().setEvaluationStat(
						UserAssignmentLink.NOT_EVALUATED);
			}
		}

	}

	public class SubmittedFiles extends Fragment {

		private IModel<Users> userModel;

		public SubmittedFiles(String id, MarkupContainer container,
				IModel<Users> userModel) {
			super(id, "usrFiles", container, userModel);
			this.userModel = userModel;
			final IModel<List<FilesUploaded>> userFilesModel = new PropertyModel<List<FilesUploaded>>(
					this, "userSubmissions");
			Label noFileLabel = new Label("noFileDiv", "No File Available.") {
				@Override
				public boolean isVisible() {
					if (userFilesModel.getObject() != null
							&& userFilesModel.getObject().size() > 0)
						return false;
					else
						return true;
				}
			};

			add(noFileLabel);

			ListView<FilesUploaded> ful = new ListView<FilesUploaded>(
					"submFile", userFilesModel) {

				@Override
				protected void populateItem(ListItem<FilesUploaded> item) {
					item.add(new ExternalLink("submFileLink", item
							.getModelObject().getFileDownloadUrl(), item
							.getModelObject().getFileOrigName()));
				}

			};
			add(ful);
		}

		public List<FilesUploaded> getUserSubmissions() {
			return new FilesUploadedDAO(getORMInterface())
					.getFilesUploadedByUser(
							new AssignmentsDAO(getORMInterface())
									.getSubmissionsDirectory(SubmittersList.this.assnModel
											.getObject()), userModel
									.getObject());
		}
	}

	public String getFilterAsString() {
		if (this.filterBy == SHOW_ALL) {
			return "<strong>No submissions yet</strong>";
		}/*
		 * else if(this.filterBy == SHOW_DEFAULTERS){ return
		 * "No <strong>defaulter</strong> exists"; }
		 */else if (this.filterBy == SHOW_EVALUATED) {
			return "No submission is evaluated";
		} else if (this.filterBy == SHOW_INTIME) {
			return "No <strong>in-time</strong> submission exists yet";
		} else if (this.filterBy == SHOW_LATE) {
			return "No <strong>late</strong> submission yet";
		} else if (this.filterBy == SHOW_NOT_EVALUATED) {
			return "No <strong>unevaluated</strong> submission exists yet";
		} else if (this.filterBy == SHOW_PENDING) {
			return "No <strong>pending</strong> submission exists yet";
		} else {
			return "No item exists";
		}
	}

}
